package trace

import (
	"context"
	"crypto/tls"
	"net/http"
	"net/http/httptrace"
	"time"
)

//noinspection GoUnusedExportedFunction
func BuildTraceRequest(req *http.Request, usedTime *UsedTime) *http.Request {

	traceCtx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
		// 开始获取连接
		GetConn: func(hostPort string) {
			usedTime.FetchConnStart = time.Now()
		},
		// 成功获取到连接，如果连接是重用的，耗时设置为0
		GotConn: func(info httptrace.GotConnInfo) {
			if info.Reused {
				// 如果是复用连接，应该在这里记录创建连接成功
				usedTime.CreateConnEnd = time.Now()
				usedTime.FetchConnUsedTime = 0
			} else {
				usedTime.FetchConnUsedTime = time.Since(usedTime.FetchConnStart).Nanoseconds()
			}
		},
		// 获取response后，将conn放回连接池重用，执行到这里，说明请求已经处理完成了。
		PutIdleConn: func(err error) {
			usedTime.FetchConnUsedTime = time.Since(usedTime.FetchResponseStart).Nanoseconds()
		},
		// 成功读取到response的第一个字节。
		GotFirstResponseByte: func() {
			usedTime.FetchResponseStart = time.Now()
			usedTime.WaitResponseUsedTime = usedTime.FetchResponseStart.UnixNano() - usedTime.SendRequestEnd.UnixNano()
		},
		// 当服务端响应100时，调用此函数，用来统计数据传输到服务端,总共传输了几次。
		Got100Continue: func() {
			usedTime.UploadNumber++
		},
		// 查找DNS开始时调用此函数
		DNSStart: func(info httptrace.DNSStartInfo) {
			usedTime.FindDnsStart = time.Now()
		},
		// 查找DNS完成时，调用此函数
		DNSDone: func(info httptrace.DNSDoneInfo) {
			if info.Err == nil {
				usedTime.FindDnsUsedTime = time.Since(usedTime.FindDnsStart).Nanoseconds()
			} else {
				usedTime.TraceErrorType = FindDnsDoneError
			}
		},
		// 开始连接服务器时，调用此函数
		ConnectStart: func(network, addr string) {
			usedTime.CreateConnStart = time.Now()
		},
		// 连接服务器成功时，调用此函数
		ConnectDone: func(network, addr string, err error) {
			if err == nil {
				usedTime.CreateConnEnd = time.Now()
				usedTime.CreateConnUsedTime = usedTime.CreateConnEnd.UnixNano() - usedTime.CreateConnStart.UnixNano()
			} else {
				usedTime.TraceErrorType = ConnectionServerError
				usedTime.CreateConnUsedTime = 0
			}

		},
		// 当TLS握手开始时，调用此函数
		TLSHandshakeStart: func() {
			usedTime.TlsHandshakeStart = time.Now()
		},
		TLSHandshakeDone: func(state tls.ConnectionState, e error) {
			usedTime.TlsHandshakeUsedTime = time.Since(usedTime.TlsHandshakeStart).Nanoseconds()
		},
		// 传输完请求头之后，调用此函数
		WroteHeaders: func() {
			usedTime.SendHeaderEnd = time.Now()
			usedTime.SendHeaderUsedTime = usedTime.SendHeaderEnd.UnixNano() - usedTime.CreateConnEnd.UnixNano()
		},
		// 如果设置了100-continue，等待服务端响应100后，调用此函数
		Wait100Continue: func() {
			usedTime.Wait100ContinueEnd = time.Now()
			usedTime.Wait100ContinueUsedTime = usedTime.Wait100ContinueEnd.UnixNano() - usedTime.SendHeaderEnd.UnixNano()
		},
		// 请求body或其他数据传输完成后，调用此函数。
		WroteRequest: func(info httptrace.WroteRequestInfo) {
			if info.Err == nil {
				usedTime.SendRequestEnd = time.Now()
				// 如果没有使用100Continue，写请求耗时=当前时间-http header传输完成的时间，否则，写请求耗时=当前时间-收到服务端100响应的时间
				if usedTime.Wait100ContinueEnd.IsZero() {
					usedTime.SendRequestUsedTime = usedTime.SendRequestEnd.UnixNano() - usedTime.SendHeaderEnd.UnixNano()
				} else {
					usedTime.SendRequestUsedTime = usedTime.SendRequestEnd.UnixNano() - usedTime.Wait100ContinueEnd.UnixNano()
				}
			} else {
				usedTime.TraceErrorType = WriteRequestError
			}
		},
	})
	return req.WithContext(traceCtx)
}
